package com.loe.router

import com.google.auto.service.AutoService
import com.squareup.javapoet.*
import javax.annotation.processing.*
import javax.lang.model.SourceVersion
import javax.lang.model.element.Modifier
import javax.lang.model.element.TypeElement
import javax.lang.model.util.Elements
import javax.lang.model.util.Types

@AutoService(Processor::class)
@SupportedSourceVersion(SourceVersion.RELEASE_8)
class RouterProcessor : AbstractProcessor()
{
    private lateinit var typeUtils: Types
    private lateinit var elementUtils: Elements
    private lateinit var mFile: Filer

    override fun init(env: ProcessingEnvironment?)
    {
        super.init(env)
        if (env == null) return
        typeUtils = env.typeUtils
        elementUtils = env.elementUtils
        mFile = env.filer
    }

    override fun process(set: MutableSet<out TypeElement>?, env: RoundEnvironment?): Boolean
    {
        if (set == null || env == null) return false

        try
        {
            val elementList = env.getElementsAnnotatedWith(Router::class.java)
            val activity = ClassName.get("android.app", "Activity")

            val string = ClassName.get(String::class.java)
            val cls = ClassName.get(Class::class.java)
            val activityClass = ParameterizedTypeName.get(ClassName.get(Class::class.java), activity)
            val stringClassMap = ParameterizedTypeName.get(ClassName.get(HashMap::class.java), string, cls)
            val classStringMap = ParameterizedTypeName.get(ClassName.get(HashMap::class.java), cls, string)

            // public class BuildRouter
            val classBuilder = TypeSpec.classBuilder("BuildRouter")
                .addJavadoc("路由生成类")
                .addAnnotation(AnnotationSpec.builder(ClassName.get("androidx.annotation", "Keep")).build())
                .addModifiers(Modifier.PUBLIC)

            // private static HashMap<String, Class> classMap = new HashMap<String, Class>();
            classBuilder.addField(
                FieldSpec.builder(stringClassMap, "classMap")
                    .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
                    .initializer("new \$T()", stringClassMap)
                    .build()
            )
            // private static HashMap<Class, String> pathMap = new HashMap<Class, String>();
            classBuilder.addField(
                FieldSpec.builder(classStringMap, "pathMap")
                    .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
                    .initializer("new \$T()", classStringMap)
                    .build()
            )
            // private static void addLinkMap(String name, Class clazz) {
            //      classMap.put(name, clazz);
            //      pathMap.put(clazz, name);
            //  }
            classBuilder.addMethod(
                MethodSpec.methodBuilder("addLinkMap")
                    .addModifiers(Modifier.PRIVATE, Modifier.STATIC) // 修饰符：private static
                    .returns(Void.TYPE) // 返回类型：void
                    .addParameter(String::class.java, "name") // 参数1：String name
                    .addParameter(Class::class.java, "clazz") // 参数2：Class clazz
                    .addStatement("classMap.put(name, clazz)") // classMap.put(name, clazz)
                    .addStatement("pathMap.put(clazz, name)") // pathMap.put(clazz, name)
                    .build()
            )

            val staticCode = CodeBlock.builder()
            for (element in elementList)
            {
                val type = element.asType()
                //拿到注解
                var path = element.getAnnotation(Router::class.java).value
                if (path.isEmpty())
                {
                    path = element.simpleName.toString().replace("Activity", "").decapitalize()
                }
                // addLinkMap("path", Class.class);
                staticCode.addStatement("addLinkMap(\$S, \$T.class)", path, type)
            }
            classBuilder.addStaticBlock(staticCode.build())

//            // public static Class<Activity> getActivity(String path)
//            classBuilder.addMethod(
//                MethodSpec.methodBuilder("getActivity")
//                    .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
//                    .addParameter(ParameterSpec.builder(string, "path").build())
//                    .addCode("return classMap.get(path);")
//                    .returns(activityClass)
//                    .build()
//            )
//
//            // public static String getPath(Class cls)
//            classBuilder.addMethod(
//                MethodSpec.methodBuilder("getPath")
//                    .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
//                    .addParameter(ParameterSpec.builder(cls, "cls").build())
//                    .addCode("return pathMap.get(cls);")
//                    .returns(string)
//                    .build()
//            )

            var packName = processingEnv.elementUtils.getPackageOf(elementList.elementAt(0)).qualifiedName.toString()
            val packNameArray = packName.split(".")
            if (packNameArray.size > 3)
            {
                packName = packNameArray[0] + "." + packNameArray[1] + "." + packNameArray[2]
            }

            // 生成类文件
            JavaFile.builder(packName, classBuilder.build())
                .build().writeTo(mFile)
        } catch (e: Exception)
        {
        }
        return false
    }

    override fun getSupportedAnnotationTypes(): MutableSet<String>
    {
        return setOf(Router::class.java.canonicalName).toMutableSet()
    }
}